package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"os"
	"sort"
	"time"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
)

// BlockAnalyzer 区块分析器
type BlockAnalyzer struct {
	client *ethclient.Client
}

// BlockInfo 区块信息结构
type BlockInfo struct {
	Number       uint64               `json:"number"`
	Hash         string               `json:"hash"`
	ParentHash   string               `json:"parentHash"`
	Timestamp    uint64               `json:"timestamp"`
	Miner        string               `json:"miner"`
	GasUsed      uint64               `json:"gasUsed"`
	GasLimit     uint64               `json:"gasLimit"`
	Difficulty   string               `json:"difficulty"`
	Size         uint64               `json:"size"`
	TxCount      int                  `json:"transactionCount"`
	Transactions []TransactionInfo    `json:"transactions"`
	ExtraData    string               `json:"extraData"`
	StateRoot    string               `json:"stateRoot"`
	ReceiptsRoot string               `json:"receiptsRoot"`
	TxRoot       string               `json:"transactionsRoot"`
	UncleCount   int                  `json:"uncleCount"`
	Uncles       []string             `json:"uncles"`
	Analysis     *BlockAnalysisResult `json:"analysis"`
}

// TransactionInfo 交易信息结构
type TransactionInfo struct {
	Hash     string `json:"hash"`
	From     string `json:"from"`
	To       string `json:"to"`
	Value    string `json:"value"`
	Gas      uint64 `json:"gas"`
	GasPrice string `json:"gasPrice"`
	GasUsed  uint64 `json:"gasUsed"`
	Status   uint64 `json:"status"`
	Type     uint8  `json:"type"`
	Nonce    uint64 `json:"nonce"`
	Data     string `json:"data"`
}

// BlockAnalysisResult 区块分析结果
type BlockAnalysisResult struct {
	TotalValue           string            `json:"totalValue"`
	AverageGasPrice      string            `json:"averageGasPrice"`
	GasUtilization       float64           `json:"gasUtilization"`
	SuccessfulTxCount    int               `json:"successfulTxCount"`
	FailedTxCount        int               `json:"failedTxCount"`
	ContractCreations    int               `json:"contractCreations"`
	TopSenders           []AddressActivity `json:"topSenders"`
	TopReceivers         []AddressActivity `json:"topReceivers"`
	TransactionTypes     map[string]int    `json:"transactionTypes"`
	GasPriceDistribution []GasPriceRange   `json:"gasPriceDistribution"`
	BlockTime            uint64            `json:"blockTime"`
}

// AddressActivity 地址活动统计
type AddressActivity struct {
	Address string `json:"address"`
	Count   int    `json:"count"`
	Value   string `json:"value"`
}

// GasPriceRange Gas 价格分布
type GasPriceRange struct {
	Range string `json:"range"`
	Count int    `json:"count"`
}

// NewBlockAnalyzer 创建区块分析器
func NewBlockAnalyzer(rpcURL string) (*BlockAnalyzer, error) {
	client, err := ethclient.Dial(rpcURL)
	if err != nil {
		return nil, fmt.Errorf("连接到以太坊节点失败: %v", err)
	}

	return &BlockAnalyzer{client: client}, nil
}

// AnalyzeBlock 分析指定区块
func (ba *BlockAnalyzer) AnalyzeBlock(blockNumber *big.Int) (*BlockInfo, error) {
	fmt.Printf("🔍 分析区块 %s...\n", blockNumber.String())

	// 获取区块信息
	block, err := ba.client.BlockByNumber(context.Background(), blockNumber)
	if err != nil {
		return nil, fmt.Errorf("获取区块失败: %v", err)
	}

	// 创建区块信息结构
	blockInfo := &BlockInfo{
		Number:       block.Number().Uint64(),
		Hash:         block.Hash().Hex(),
		ParentHash:   block.ParentHash().Hex(),
		Timestamp:    block.Time(),
		Miner:        block.Coinbase().Hex(),
		GasUsed:      block.GasUsed(),
		GasLimit:     block.GasLimit(),
		Difficulty:   block.Difficulty().String(),
		Size:         block.Size(),
		TxCount:      len(block.Transactions()),
		ExtraData:    fmt.Sprintf("0x%x", block.Extra()),
		StateRoot:    block.Root().Hex(),
		ReceiptsRoot: block.ReceiptHash().Hex(),
		TxRoot:       block.TxHash().Hex(),
		UncleCount:   len(block.Uncles()),
	}

	// 处理叔块
	for _, uncle := range block.Uncles() {
		blockInfo.Uncles = append(blockInfo.Uncles, uncle.Hash().Hex())
	}

	// 分析交易
	transactions, analysis, err := ba.analyzeTransactions(block)
	if err != nil {
		return nil, fmt.Errorf("分析交易失败: %v", err)
	}

	blockInfo.Transactions = transactions
	blockInfo.Analysis = analysis

	// 计算区块时间间隔
	if blockNumber.Uint64() > 0 {
		parentBlock, err := ba.client.BlockByNumber(context.Background(), big.NewInt(int64(blockNumber.Uint64()-1)))
		if err == nil {
			blockInfo.Analysis.BlockTime = block.Time() - parentBlock.Time()
		}
	}

	return blockInfo, nil
}

// analyzeTransactions 分析区块中的交易
func (ba *BlockAnalyzer) analyzeTransactions(block *types.Block) ([]TransactionInfo, *BlockAnalysisResult, error) {
	var transactions []TransactionInfo
	analysis := &BlockAnalysisResult{
		TransactionTypes:     make(map[string]int),
		GasPriceDistribution: make([]GasPriceRange, 0),
	}

	totalValue := big.NewInt(0)
	totalGasPrice := big.NewInt(0)
	senderMap := make(map[string]*AddressActivity)
	receiverMap := make(map[string]*AddressActivity)
	gasPriceMap := make(map[string]int)

	for _, tx := range block.Transactions() {
		// 获取交易收据
		receipt, err := ba.client.TransactionReceipt(context.Background(), tx.Hash())
		if err != nil {
			log.Printf("获取交易收据失败 %s: %v", tx.Hash().Hex(), err)
			continue
		}

		// 获取发送者地址
		from, err := ba.client.TransactionSender(context.Background(), tx, block.Hash(), receipt.TransactionIndex)
		if err != nil {
			log.Printf("获取交易发送者失败 %s: %v", tx.Hash().Hex(), err)
			continue
		}

		// 创建交易信息
		txInfo := TransactionInfo{
			Hash:     tx.Hash().Hex(),
			From:     from.Hex(),
			Value:    tx.Value().String(),
			Gas:      tx.Gas(),
			GasPrice: tx.GasPrice().String(),
			GasUsed:  receipt.GasUsed,
			Status:   receipt.Status,
			Type:     tx.Type(),
			Nonce:    tx.Nonce(),
			Data:     fmt.Sprintf("0x%x", tx.Data()),
		}

		if tx.To() != nil {
			txInfo.To = tx.To().Hex()
		} else {
			txInfo.To = "0x0000000000000000000000000000000000000000" // 合约创建
			analysis.ContractCreations++
		}

		transactions = append(transactions, txInfo)

		// 统计分析数据
		totalValue.Add(totalValue, tx.Value())
		totalGasPrice.Add(totalGasPrice, tx.GasPrice())

		// 统计交易状态
		if receipt.Status == 1 {
			analysis.SuccessfulTxCount++
		} else {
			analysis.FailedTxCount++
		}

		// 统计发送者活动
		if activity, exists := senderMap[from.Hex()]; exists {
			activity.Count++
			value := new(big.Int)
			value.SetString(activity.Value, 10)
			value.Add(value, tx.Value())
			activity.Value = value.String()
		} else {
			senderMap[from.Hex()] = &AddressActivity{
				Address: from.Hex(),
				Count:   1,
				Value:   tx.Value().String(),
			}
		}

		// 统计接收者活动
		if tx.To() != nil {
			toAddr := tx.To().Hex()
			if activity, exists := receiverMap[toAddr]; exists {
				activity.Count++
				value := new(big.Int)
				value.SetString(activity.Value, 10)
				value.Add(value, tx.Value())
				activity.Value = value.String()
			} else {
				receiverMap[toAddr] = &AddressActivity{
					Address: toAddr,
					Count:   1,
					Value:   tx.Value().String(),
				}
			}
		}

		// 统计交易类型
		txType := fmt.Sprintf("Type %d", tx.Type())
		analysis.TransactionTypes[txType]++

		// 统计 Gas 价格分布
		gasPriceRange := ba.getGasPriceRange(tx.GasPrice())
		gasPriceMap[gasPriceRange]++
	}

	// 计算平均值和统计信息
	if len(transactions) > 0 {
		analysis.TotalValue = totalValue.String()
		avgGasPrice := new(big.Int).Div(totalGasPrice, big.NewInt(int64(len(transactions))))
		analysis.AverageGasPrice = avgGasPrice.String()
	}

	// 计算 Gas 利用率
	if block.GasLimit() > 0 {
		analysis.GasUtilization = float64(block.GasUsed()) / float64(block.GasLimit()) * 100
	}

	// 排序并获取 Top 活跃地址
	analysis.TopSenders = ba.getTopAddresses(senderMap, 5)
	analysis.TopReceivers = ba.getTopAddresses(receiverMap, 5)

	// 构建 Gas 价格分布
	for priceRange, count := range gasPriceMap {
		analysis.GasPriceDistribution = append(analysis.GasPriceDistribution, GasPriceRange{
			Range: priceRange,
			Count: count,
		})
	}

	// 排序 Gas 价格分布
	sort.Slice(analysis.GasPriceDistribution, func(i, j int) bool {
		return analysis.GasPriceDistribution[i].Count > analysis.GasPriceDistribution[j].Count
	})

	return transactions, analysis, nil
}

// getGasPriceRange 获取 Gas 价格范围
func (ba *BlockAnalyzer) getGasPriceRange(gasPrice *big.Int) string {
	gwei := new(big.Int).Div(gasPrice, big.NewInt(1e9))

	switch {
	case gwei.Cmp(big.NewInt(1)) < 0:
		return "< 1 Gwei"
	case gwei.Cmp(big.NewInt(5)) < 0:
		return "1-5 Gwei"
	case gwei.Cmp(big.NewInt(10)) < 0:
		return "5-10 Gwei"
	case gwei.Cmp(big.NewInt(20)) < 0:
		return "10-20 Gwei"
	case gwei.Cmp(big.NewInt(50)) < 0:
		return "20-50 Gwei"
	case gwei.Cmp(big.NewInt(100)) < 0:
		return "50-100 Gwei"
	default:
		return "> 100 Gwei"
	}
}

// getTopAddresses 获取 Top 活跃地址
func (ba *BlockAnalyzer) getTopAddresses(addressMap map[string]*AddressActivity, limit int) []AddressActivity {
	var addresses []AddressActivity

	for _, activity := range addressMap {
		addresses = append(addresses, *activity)
	}

	// 按交易数量排序
	sort.Slice(addresses, func(i, j int) bool {
		return addresses[i].Count > addresses[j].Count
	})

	if len(addresses) > limit {
		addresses = addresses[:limit]
	}

	return addresses
}

// AnalyzeBlockRange 分析区块范围
func (ba *BlockAnalyzer) AnalyzeBlockRange(fromBlock, toBlock uint64) ([]*BlockInfo, error) {
	if fromBlock > toBlock {
		return nil, fmt.Errorf("起始区块号不能大于结束区块号")
	}

	var blockInfos []*BlockInfo

	fmt.Printf("🔍 分析区块范围 %d - %d\n", fromBlock, toBlock)

	for i := fromBlock; i <= toBlock; i++ {
		blockInfo, err := ba.AnalyzeBlock(big.NewInt(int64(i)))
		if err != nil {
			log.Printf("分析区块 %d 失败: %v", i, err)
			continue
		}

		blockInfos = append(blockInfos, blockInfo)
		fmt.Printf("   ✅ 区块 %d 分析完成 (交易数: %d)\n", i, blockInfo.TxCount)
	}

	return blockInfos, nil
}

// SaveAnalysisToFile 保存分析结果到文件
func (ba *BlockAnalyzer) SaveAnalysisToFile(blockInfo *BlockInfo, filename string) error {
	data, err := json.MarshalIndent(blockInfo, "", "  ")
	if err != nil {
		return fmt.Errorf("序列化数据失败: %v", err)
	}

	err = os.WriteFile(filename, data, 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %v", err)
	}

	fmt.Printf("📄 分析结果已保存到: %s\n", filename)
	return nil
}

// PrintBlockSummary 打印区块摘要
func (ba *BlockAnalyzer) PrintBlockSummary(blockInfo *BlockInfo) {
	fmt.Printf("\n📦 区块 %d 分析摘要\n", blockInfo.Number)
	fmt.Printf("═══════════════════════════════════════\n")
	fmt.Printf("区块哈希: %s\n", blockInfo.Hash)
	fmt.Printf("时间戳: %s\n", time.Unix(int64(blockInfo.Timestamp), 0).Format("2006-01-02 15:04:05"))
	fmt.Printf("矿工: %s\n", blockInfo.Miner)
	fmt.Printf("区块大小: %d bytes\n", blockInfo.Size)
	fmt.Printf("交易数量: %d\n", blockInfo.TxCount)
	fmt.Printf("Gas 使用量: %d / %d (%.2f%%)\n",
		blockInfo.GasUsed, blockInfo.GasLimit, blockInfo.Analysis.GasUtilization)

	if blockInfo.Analysis != nil {
		fmt.Printf("\n📊 交易分析\n")
		fmt.Printf("───────────────────────────────────────\n")
		fmt.Printf("成功交易: %d\n", blockInfo.Analysis.SuccessfulTxCount)
		fmt.Printf("失败交易: %d\n", blockInfo.Analysis.FailedTxCount)
		fmt.Printf("合约创建: %d\n", blockInfo.Analysis.ContractCreations)

		if blockInfo.Analysis.TotalValue != "0" {
			totalEth := weiToEther(blockInfo.Analysis.TotalValue)
			fmt.Printf("总转账金额: %s ETH\n", totalEth)
		}

		if blockInfo.Analysis.AverageGasPrice != "0" {
			avgGwei := weiToGwei(blockInfo.Analysis.AverageGasPrice)
			fmt.Printf("平均 Gas 价格: %s Gwei\n", avgGwei)
		}

		if blockInfo.Analysis.BlockTime > 0 {
			fmt.Printf("区块间隔: %d 秒\n", blockInfo.Analysis.BlockTime)
		}

		// 打印 Top 发送者
		if len(blockInfo.Analysis.TopSenders) > 0 {
			fmt.Printf("\n🏆 Top 发送者\n")
			fmt.Printf("───────────────────────────────────────\n")
			for i, sender := range blockInfo.Analysis.TopSenders {
				if i >= 3 { // 只显示前3名
					break
				}
				eth := weiToEther(sender.Value)
				fmt.Printf("%d. %s (交易数: %d, 金额: %s ETH)\n",
					i+1, sender.Address[:10]+"...", sender.Count, eth)
			}
		}

		// 打印交易类型分布
		if len(blockInfo.Analysis.TransactionTypes) > 0 {
			fmt.Printf("\n📈 交易类型分布\n")
			fmt.Printf("───────────────────────────────────────\n")
			for txType, count := range blockInfo.Analysis.TransactionTypes {
				fmt.Printf("%s: %d\n", txType, count)
			}
		}
	}
	fmt.Printf("═══════════════════════════════════════\n")
}

// weiToEther 将 wei 转换为 ether 字符串
func weiToEther(weiStr string) string {
	wei := new(big.Int)
	wei.SetString(weiStr, 10)

	ether := new(big.Float)
	ether.SetInt(wei)
	ether.Quo(ether, big.NewFloat(1e18))

	return ether.Text('f', 6)
}

// weiToGwei 将 wei 转换为 gwei 字符串
func weiToGwei(weiStr string) string {
	wei := new(big.Int)
	wei.SetString(weiStr, 10)

	gwei := new(big.Float)
	gwei.SetInt(wei)
	gwei.Quo(gwei, big.NewFloat(1e9))

	return gwei.Text('f', 2)
}

// DemoBlockAnalysis 演示区块分析功能
func DemoBlockAnalysis() {
	fmt.Println("🚀 开始区块链分析演示...")

	// 创建区块分析器
	analyzer, err := NewBlockAnalyzer("http://localhost:8545")
	if err != nil {
		log.Fatalf("创建区块分析器失败: %v", err)
	}

	// 获取最新区块号
	latestBlock, err := analyzer.client.BlockNumber(context.Background())
	if err != nil {
		log.Fatalf("获取最新区块号失败: %v", err)
	}

	fmt.Printf("📈 当前最新区块: %d\n", latestBlock)

	if latestBlock == 0 {
		fmt.Println("⚠️  区块链中还没有区块，请先启动挖矿或发送交易")
		return
	}

	// 分析最新区块
	fmt.Println("\n=== 分析最新区块 ===")
	blockInfo, err := analyzer.AnalyzeBlock(big.NewInt(int64(latestBlock)))
	if err != nil {
		log.Fatalf("分析区块失败: %v", err)
	}

	// 打印区块摘要
	analyzer.PrintBlockSummary(blockInfo)

	// 保存分析结果
	filename := fmt.Sprintf("block_%d_analysis.json", latestBlock)
	err = analyzer.SaveAnalysisToFile(blockInfo, filename)
	if err != nil {
		log.Printf("保存分析结果失败: %v", err)
	}

	// 如果有多个区块，分析最近几个区块
	if latestBlock >= 3 {
		fmt.Println("\n=== 分析最近 3 个区块 ===")
		fromBlock := latestBlock - 2
		blockInfos, err := analyzer.AnalyzeBlockRange(fromBlock, latestBlock)
		if err != nil {
			log.Printf("分析区块范围失败: %v", err)
		} else {
			// 打印范围统计
			totalTxs := 0
			totalGasUsed := uint64(0)
			for _, info := range blockInfos {
				totalTxs += info.TxCount
				totalGasUsed += info.GasUsed
			}

			fmt.Printf("\n📊 区块范围统计 (%d-%d)\n", fromBlock, latestBlock)
			fmt.Printf("═══════════════════════════════════════\n")
			fmt.Printf("总区块数: %d\n", len(blockInfos))
			fmt.Printf("总交易数: %d\n", totalTxs)
			fmt.Printf("总 Gas 使用量: %d\n", totalGasUsed)
			fmt.Printf("平均每区块交易数: %.2f\n", float64(totalTxs)/float64(len(blockInfos)))
		}
	}

	fmt.Println("\n🎉 区块链分析演示完成！")
}

func main() {
	DemoBlockAnalysis()
}
